package com.cd.music.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.cd.music.annotation.Parameter;
import com.cd.music.annotation.RequestLimit;
import com.cd.music.utils.RequestLimitUtil;
import com.cd.music.utils.StringUtil;
import org.springframework.context.annotation.Scope;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author yxl 余秀良
 * @version 1.0
 * @description: 请求拦截器
 * @date 2018年01月18日  下午4:26
 * @address: 四川成都
 */
@Scope(value = "singleton")
public class RequestInterceptor implements HandlerMethodArgumentResolver {
    private final static String DATA = "data";
    private static final String NULL = "null";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(Parameter.class) != null || parameter.getMethodAnnotation(RequestLimit.class) != null;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws UnsupportedEncodingException, InvocationTargetException, IllegalAccessException, InstantiationException, IntrospectionException {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        Class<?> parameterType = parameter.getParameterType();
        if (request != null) {
            if (parameter.getMethodAnnotation(RequestLimit.class) != null) {
                RequestLimitUtil.execute(parameter, request);
            }
            if (parameter.getParameterAnnotation(Parameter.class) != null) {
                request.setCharacterEncoding("UTF-8");
                String method = request.getMethod();
                String methodStatus = "GET";
                if (!methodStatus.equals(method)) {
                    String params = request.getParameter("request");
                    if (params != null && !"".equals(params) && !NULL.equals(params)) {
                        Map paramsMap = JSON.parseObject(params, Map.class);
                        if (paramsMap.containsKey(DATA)) {
                            String data = paramsMap.get(DATA) + "";
                            if (!StringUtil.isEmpty(data)) {
                                if (parameterType.isArray()) {
                                    if (JSONArray.parseArray(data, parameterType) != null) {
                                        return JSONArray.parseArray(data, parameterType);
                                    }
                                } else {
                                    return JSON.parseObject(data, parameterType);
                                }
                            } else {
                                throw new NullPointerException("data参数为空");
                            }
                        } else {
                            throw new NullPointerException("缺少data参数");
                        }
                    }
                } else {
                    Map<String, String[]> parameterMap = request.getParameterMap();
                    // 获取类属性
                    BeanInfo beanInfo = Introspector.getBeanInfo(parameterType);
                    // 创建 JavaBean 对象
                    Object bean = parameterType.newInstance();
                    PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                    for (PropertyDescriptor descriptor : propertyDescriptors) {
                        String propertyName = descriptor.getName();
                        if (parameterMap.containsKey(propertyName)) {
                            String[] value = parameterMap.get(propertyName);
                            Method writeMethod = descriptor.getWriteMethod();
                            Class<?> aClass = writeMethod.getParameterTypes()[0];
                            String s = value[0];
                            if (aClass.equals(Integer.class)) {
                                writeMethod.invoke(bean, Integer.parseInt(s));
                            } else {
                                writeMethod.invoke(bean, s);
                            }
                        }
                    }
                    return bean;
                }
            }
        }
        return null;
    }
}
